CleanStat used service request (SR) data from Salesforce and work order data from the CHIP work management system to determine possible “hotspots” for illegal dumping and other cleanliness issues. Salesforce and CHIP have the same address encoding, so joining the two datasets on address is possible.

There are multiple types of service requests and work orders that pertain to illegal dumping and cleanliness issues. CitiStat considered two groupings: Inspections/Investigations (residents identifying locations of possible illegal dumping) and cleanup (service requests and work orders pertaining to actual cleanup work performed by DPW).

Inspections/Investigations

Cleaning Activities

knitr::opts_chunk$set(echo = T, 
                      warning = F, 
                      message = F,
                      include = T,
                      fig.width = 10,
                      fig.height = 5)
library(tidyverse)
#library(ggiteam)
library(lubridate)
library(readxl)
library(rgdal)
library(leaflet)

iteam.colors <- c(
  "#EAAB00", # yellow
  "#666666", # med gray
  "#5EB5CB", # blue
  "#981E32", # maroon
  "#0A83A1", # dark blue
  "#f4d57f"  # pale yellow
)
dpw_facilities <- c("417 E FAYETTE ST",
                    "3939 REISTERSTOWN RD",
                    "3411 BANK ST",
                    "5225 YORK RD")
sf <- sf_sw %>% 
  bind_rows(sf_hcd) %>%
  bind_rows(sf_siu) %>%
  bind_rows(sf_dirty) %>%
  replace_na(list(`Block Number` = "", `Street No` = "", `Street Name` = "")) %>%
  mutate(date_opened = as.Date(as.numeric(`Opened Date`), origin = "1899-12-30"),
         lat = as.numeric(`Location (Latitude)`),
         long = as.numeric(`Location (Longitude)`),
         street_address = paste(`Street No`, `Street Name`)) %>%
  rename(street_name = `Street Name`) %>% 
  left_join(real_prop, by = c("street_address" = "PropertyAddress")) %>%
  mutate(street_num = as.numeric(`Street No`))

wo_sql <- wo_sql %>%
  mutate(`Clean Type` = ifelse(is.na(`Clean Type`), 
                               "BOARDING (not cleaning)", 
                               `Clean Type`)) %>%
  replace_na(list(Direction = "", `Street Name` = "", `Street Attr` = "")) %>%
  mutate(date_created = as.Date(`Date Create`),
         street_address = paste(`House Number`, Direction, `Street Name`, `Street Attr`),
         street_name = paste(Direction, `Street Name`, `Street Attr`),
         street_num = as.numeric(`House Number`))
sf_address_counts <- sf %>% 
  filter(
         date_opened >= "2018-01-01",
         !is.na(street_num),
         !is.na(street_name),
         !(street_address %in% dpw_facilities)) %>%
  count(Block, street_num, street_name, `Service Request Type`) %>%
  spread(key = `Service Request Type`, 
         value = n) %>%
  replace_na(list(`HCD-Illegal Dumping` = 0,
                  `HCD-Sanitation Property` = 0,
                  `HCD-Vacant Building` = 0,
                  `SW-Boarding` = 0,
                  `SW-Cleaning` = 0,
                  `SW-HGW` = 0,
                  `SW-SIU Clean Up` = 0,
                  `SW-Dirty Alley` = 0,
                  `SW-Dirty Street` = 0,
                  `SW-Dirty Alley Proactive` = 0,
                  `SW-Dirty Street Proactive` = 0)) %>%
  mutate(sf_count = `HCD-Illegal Dumping` +
           `HCD-Sanitation Property` +
           `HCD-Vacant Building` +
           `SW-Boarding` +
           `SW-Cleaning` +
           `SW-HGW` +
           `SW-SIU Clean Up` +
           `SW-Dirty Alley` +
           `SW-Dirty Street` +
           `SW-Dirty Alley Proactive` +
           `SW-Dirty Street Proactive`

  )
wo_address_counts <- wo_sql %>% 
  filter(date_created >= "2018-01-01",
         `Clean Type` %in% c("HIGH GRASS & WEEDS",
                          "TRASH & DEBRIS",
                          "TRASH, DEBRIS, HIGH GRASS & WEEDS",
                          "BOARDING (not cleaning)"),
         !is.na(street_address),
         !grepl("Descriptive", street_name),
         !(street_address %in% dpw_facilities)) %>%
  count(Block, street_num, street_name, `Clean Type`) %>% 
  spread(key = `Clean Type`, value = n) %>%
  replace_na(list(
    "HIGH GRASS & WEEDS" = 0 ,
    "TRASH & DEBRIS" = 0,
    "TRASH, DEBRIS, HIGH GRASS & WEEDS" = 0,
    "BOARDING (not cleaning)" = 0)) %>%
  mutate(wo_count = `HIGH GRASS & WEEDS` + 
           `TRASH & DEBRIS` +
           `TRASH, DEBRIS, HIGH GRASS & WEEDS` +
           `BOARDING (not cleaning)`)

wo_cat23_address_counts <- wo_sql %>% 
  filter(date_created >= "2018-01-01",
         `Clean Type` %in% c("HIGH GRASS & WEEDS",
                          "TRASH & DEBRIS",
                          "TRASH, DEBRIS, HIGH GRASS & WEEDS",
                          "BOARDING (not cleaning)"),
         !is.na(street_address),
         !grepl("Descriptive", street_name),
         !(street_address %in% dpw_facilities),
         `Clean Size` %in% c(2, 3)) %>%
  count(Block, street_num, street_name, `Clean Type`) %>% 
  spread(key = `Clean Type`, value = n) %>%
  replace_na(list(
    "HIGH GRASS & WEEDS" = 0 ,
    "TRASH & DEBRIS" = 0,
    "TRASH, DEBRIS, HIGH GRASS & WEEDS" = 0,
    "BOARDING (not cleaning)" = 0)) %>%
  rename(hgw_cat23 = "HIGH GRASS & WEEDS",
         td_cat23 = "TRASH & DEBRIS",
         td_hgw_cat23 = "TRASH, DEBRIS, HIGH GRASS & WEEDS") %>%
  mutate(wo_cat23_count = hgw_cat23 + td_cat23 + td_hgw_cat23)

Counts by Address

address_counts_join <- wo_address_counts %>%
  full_join(sf_address_counts, 
            by = c("street_num", "street_name")) %>%
  full_join(wo_cat23_address_counts %>% 
              select(
                street_num,
                street_name,
                hgw_cat23,
                td_cat23,
                td_hgw_cat23,
                wo_cat23_count
              ), 
            by = c("street_num", "street_name")) %>%
  replace_na(list(
    `HIGH GRASS & WEEDS` = 0,
    `TRASH & DEBRIS` = 0,
    `TRASH, DEBRIS, HIGH GRASS & WEEDS` = 0,
    `BOARDING (not cleaning)` = 0,
    `HCD-Illegal Dumping` = 0,
    `HCD-Sanitation Property` = 0,
    `HCD-Vacant Building` = 0,
    `SW-Boarding` = 0,
    `SW-Cleaning` = 0,
    `SW-HGW` = 0,
    `SW-SIU Clean Up` = 0,
    `SW-Dirty Alley` = 0,
    `SW-Dirty Street` = 0,
    `SW-Dirty Alley Proactive` = 0,
    `SW-Dirty Street Proactive` = 0,
    wo_count = 0,
    sf_count = 0,
    hgw_cat23 = 0,
    td_cat23 = 0,
    td_hgw_cat23 = 0,
    wo_cat23_count = 0)) %>%
  mutate(all_events = wo_count + sf_count,
         diff_events = wo_count - sf_count,
         Block = ifelse(!is.na(Block.x), Block.x, Block.y),
         reporting = `HCD-Illegal Dumping` + `HCD-Sanitation Property`,
         cleanup =  `SW-Dirty Alley` + `SW-Dirty Street` + 
         `SW-Dirty Alley Proactive` + `SW-Dirty Street Proactive`
         + `SW-SIU Clean Up` + wo_cat23_count)

address_counts_join

Counts by Block

block_counts <- address_counts_join %>%
  filter(!is.na(Block)) %>%
  select(-street_num, -street_name, -Block.x, -Block.y, -diff_events) %>%
  group_by(Block) %>%
  summarise_all(sum, na.rm=T) %>%
  ungroup() %>%
  arrange(desc(all_events)) 

block_counts

Belows is a cumulative percentage plot showing the number of blocks responsible for a given percentage of category 3 work orders.

189 blocks, or 14% of all blocks receiving a category 3 work order since January 1, 2018, are responsible for 50% of all category 3 work orders.

x <- 0.25
# Responsible for 50% of work orders
wo_cum <- wo_sql %>%
  filter(`Clean Size` == 3,
         date_created >= "2018-01-01",
         `Clean Type` %in% c("HIGH GRASS & WEEDS",
                             "TRASH & DEBRIS",
                             "TRASH, DEBRIS, HIGH GRASS & WEEDS"),
         #!is.na(street_address),
         !grepl("Descriptive", street_name),
         !(street_address %in% dpw_facilities)) %>%
  count(Block) %>%
  arrange(desc(n)) %>%
  mutate(row_n = row_number(),
         cum_blocks = row_n / max(row_n),
         cumsum_sr = cumsum(n),
         cumpct_sr = cumsum_sr / sum(n))

wo_cum_50pct <- wo_cum %>%
  filter(abs(x - cumpct_sr) == min(abs(x - cumpct_sr))) %>%
  select(row_n) %>%
  pull()

wo_cum %>%
  ggplot(aes(row_n, cumpct_sr)) +
  geom_line() +
  theme_minimal() +
  #theme_iteam_google_docs() +
  scale_y_continuous(labels = scales::percent) +
  labs(x = "Number of City Blocks",
       y = "% Category 3 Cleaning")

wo_cum_50pct_df <- wo_cum %>%
  filter(row_n <=wo_cum_50pct)

wo_cum_50pct_parcels <- subset(parcels, parcels$BLOCKNUM %in%
                                         wo_cum_50pct_df$Block)

Map

block_top100_reporting <- block_counts %>%
  arrange(desc(reporting)) %>%
  top_n(100, reporting) %>%
  mutate(id_rank = row_number())

block_top100_cleanup <- block_counts %>%
  arrange(desc(cleanup)) %>%
  top_n(100, cleanup) %>%
  mutate(id_rank = row_number())

block_top100_reporting_cleanup <- block_top100_reporting %>%
  inner_join(block_top100_cleanup, by = "Block")
block_top100_reporting_parcels <- subset(parcels, parcels$BLOCKNUM %in%
                                         block_top100_reporting$Block)

block_top100_cleanup_parcels <- subset(parcels, parcels$BLOCKNUM %in%
                                    block_top100_cleanup$Block)

open_wo <- wo_sql %>% filter(Status %in% c("NEW", "PENDING"),
                             !is.na(Latitude)) %>%
  mutate(Latitude = as.numeric(Latitude),
         Longitude = as.numeric(Longitude))

open_sr <- sf %>% filter(is.na(`Closed Date`),
                         `Date/Time Opened` >= "2018-01-01",
                         !is.na(`Location (Latitude)`)) %>%
  mutate(`Location (Latitude)` = as.numeric(`Location (Latitude)`),
         `Location (Longitude)` = as.numeric(`Location (Longitude)`))
library(htmltools)
top_street_segments <- subset(street_segments)

map_colors <- c("black",
                iteam.colors[5],
                iteam.colors[1],
                iteam.colors[4],
                #"blue",
                #"red",
                iteam.colors[3])

map_labels <- c("Quadrant",
                "Top 100 for Inspection/Investigation", 
                "Top 100 for Cleaning Activity",
                "50% of Cat 3 Work Orders",
                #"Open Work Orders",
                #"Open Service Requests",
                "Neighborhoods")

open_wo_labels <- paste0("Open Work Order", "<br>",
                         open_wo$`Street Address`, "<br>",
                         open_wo$`Property Owner`, "<br>",
                         open_wo$`Work Order Type`, "<br>",
                         open_wo$`Clean Type`, "<br>",
                         "Category: ", open_wo$`Clean Size`)

open_sr_labels <- paste0("Open Service Request <br>",
                         open_sr$street_address, "<br>",
                         open_sr$`Service Request Type`, "<br>",
                         open_sr$`Activity Assigned To`, "<br>",
                         "Date Openend: ", open_sr$`Opened Date`)
leaflet() %>%
  setView(lng = -76.6, lat = 39.3, zoom = 12) %>%
  addProviderTiles(providers$Stamen.TonerLite) %>% 
    addPolygons(data = quads,
              fillOpacity = 0,
              opacity = 1,
              color = "black",
              weight = 3,
              group = map_labels[1]) %>%
  addPolygons(data = hoods,
              fillOpacity = 0,
              opacity = 1,
              color = map_colors[5],
              weight = 1.5,
              group = map_labels[5],
              label = ~hoods$label) %>%
  addPolygons(data = block_top100_reporting_parcels,
              fillOpacity = 0.6,
              fillColor = map_colors[2],
              opacity = 0,
              group = map_labels[2]) %>%
  addPolygons(data = block_top100_cleanup_parcels,
              fillOpacity = 0.6,
              fillColor = map_colors[3],
              opacity = 0,
              group = map_labels[3]) %>%
    addPolygons(data = wo_cum_50pct_parcels,
              fillOpacity = 0.6,
              fillColor = map_colors[4],
              opacity = 0,
              group = map_labels[4]) %>%
  # addCircleMarkers(data = open_wo,
  #                  lat = open_wo$Latitude,
  #                  lng = open_wo$Longitude,
  #                  radius = 2,
  #                  label = ~lapply(open_wo_labels, HTML),
  #                  group = map_labels[5],
  #                  fillColor = map_colors[5],
  #                  opacity = 0) %>%
  #   addCircleMarkers(data = open_sr,
  #                  lat = open_sr$`Location (Latitude)`,
  #                  lng = open_sr$`Location (Longitude)`,
  #                  radius = 2,
  #                  label = ~lapply(open_sr_labels, HTML),
  #                  group = map_labels[6],
  #                  fillColor = map_colors[6],
  #                  opacity = 0) %>%
  addLayersControl(overlayGroups = map_labels) %>%
  addLegend(position = "bottomright",
            colors = map_colors,
            labels = map_labels)

NA
LS0tCnRpdGxlOiAiSWxsZWdhbCBEdW1waW5nL0NsZWFuaW5nIEhvdHNwb3RzIgphdXRob3I6ICJKdXN0aW4gRWxzemFzeiIKZW1haWw6ICJqdXN0aW4uZWxzemFzekBiYWx0aW1vcmVjaXR5LmdvdiIKZGF0ZTogIlR1ZXNkYXksIEF1Z3VzdCA2LCAyMDE5IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZmlnX2hlaWdodDogNQogICAgZmlnX3dpZHRoOiAxMAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCkNsZWFuU3RhdCB1c2VkIHNlcnZpY2UgcmVxdWVzdCAoU1IpIGRhdGEgZnJvbSBTYWxlc2ZvcmNlIGFuZCB3b3JrIG9yZGVyIGRhdGEgZnJvbSB0aGUgQ0hJUCB3b3JrIG1hbmFnZW1lbnQgc3lzdGVtIHRvIGRldGVybWluZSBwb3NzaWJsZSAiaG90c3BvdHMiIGZvciBpbGxlZ2FsIGR1bXBpbmcgYW5kIG90aGVyIGNsZWFubGluZXNzIGlzc3Vlcy4gU2FsZXNmb3JjZSBhbmQgQ0hJUCBoYXZlIHRoZSBzYW1lIGFkZHJlc3MgZW5jb2RpbmcsIHNvIGpvaW5pbmcgdGhlIHR3byBkYXRhc2V0cyBvbiBhZGRyZXNzIGlzIHBvc3NpYmxlLiAKClRoZXJlIGFyZSBtdWx0aXBsZSB0eXBlcyBvZiBzZXJ2aWNlIHJlcXVlc3RzIGFuZCB3b3JrIG9yZGVycyB0aGF0IHBlcnRhaW4gdG8gaWxsZWdhbCBkdW1waW5nIGFuZCBjbGVhbmxpbmVzcyBpc3N1ZXMuIENpdGlTdGF0IGNvbnNpZGVyZWQgdHdvIGdyb3VwaW5nczogKipJbnNwZWN0aW9ucy9JbnZlc3RpZ2F0aW9ucyoqIChyZXNpZGVudHMgaWRlbnRpZnlpbmcgbG9jYXRpb25zIG9mIHBvc3NpYmxlIGlsbGVnYWwgZHVtcGluZykgYW5kICoqY2xlYW51cCoqIChzZXJ2aWNlIHJlcXVlc3RzIGFuZCB3b3JrIG9yZGVycyBwZXJ0YWluaW5nIHRvIGFjdHVhbCBjbGVhbnVwIHdvcmsgcGVyZm9ybWVkIGJ5IERQVykuCgoqKkluc3BlY3Rpb25zL0ludmVzdGlnYXRpb25zKioKCi0gU1I6IEhDRC1JbGxlZ2FsIER1bXBpbmcKLSBTUjogSENELVNhbml0YXRpb24gUHJvcGVydHkKCioqQ2xlYW5pbmcgQWN0aXZpdGllcyoqCgotIFNSOiBTVy1EaXJ0eSBBbGxleQotIFNSOiBTVy1EaXJ0eSBTdHJlZXQKLSAqU1I6IFNXLUNsZWFuaW5nIChSRU1PVkVEIC0gRFVQTElDQVRJVkUgT0YgV09SSyBPUkRFUlMpKgotIFNSOiBTVy1TSVUgQ2xlYW4tVXAKLSBXTzogQWxsIENhdGVnb3J5IDIgJiAzIENsZWFuaW5nIAoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBULCBlY2hvID0gVCwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IFRSVUV9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRiwKICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUgPSBULAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gNSkKYGBgCgpgYGB7ciBsaWJyYXJpZXN9CmxpYnJhcnkodGlkeXZlcnNlKQojbGlicmFyeShnZ2l0ZWFtKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkocmdkYWwpCmxpYnJhcnkobGVhZmxldCkKCml0ZWFtLmNvbG9ycyA8LSBjKAogICIjRUFBQjAwIiwgIyB5ZWxsb3cKICAiIzY2NjY2NiIsICMgbWVkIGdyYXkKICAiIzVFQjVDQiIsICMgYmx1ZQogICIjOTgxRTMyIiwgIyBtYXJvb24KICAiIzBBODNBMSIsICMgZGFyayBibHVlCiAgIiNmNGQ1N2YiICAjIHBhbGUgeWVsbG93CikKYGBgCgpgYGB7ciBsb2FkX2RhdGEsIGVjaG8gPSBGfQojIHJlYWQgc2FsZXNmb3JjZSBzZXJ2aWNlIHJlcXVlc3RzCnNmX3N3IDwtIHJlYWRfZXhjZWwoIi4uL2RhdGEvcmF3L3NhbGVzZm9yY2UvQ2xlYW5TdGF0X1NXXzMxMV9zYWxlc2ZvcmNlLnhsc3giLAogICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9ICJ0ZXh0IiwKICAgICAgICAgICAgICAgICBuYSA9IGMoIiNFUlJPUiIpKQogIApzZl9oY2QgPC0gcmVhZF9leGNlbCgiLi4vZGF0YS9yYXcvc2FsZXNmb3JjZS9DbGVhblN0YXRfSENEXzMxMV9zYWxlc2ZvcmNlLnhsc3giLAogICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSAidGV4dCIsCiAgICAgICAgICAgICAgICAgICAgIG5hID0gYygiI0VSUk9SIikpCgpzZl9zaXUgPC0gcmVhZF9leGNlbCgiLi4vZGF0YS9yYXcvc2FsZXNmb3JjZS9TV19TSVVfQ2xlYW5fVXBfc2FsZXNmb3JjZS54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gInRleHQiLAogICAgICAgICAgICAgICAgICAgICBuYSA9IGMoIiNFUlJPUiIpKQoKc2ZfZGlydHkgPC0gcmVhZF9leGNlbCgiLi4vZGF0YS9yYXcvc2FsZXNmb3JjZS9TV19EaXJ0eUFsbGV5X0RpcnR5U3RyZWV0XzMxMV9zYWxlc2ZvcmNlLnhsc3giLAogICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSAidGV4dCIsCiAgICAgICAgICAgICAgICAgICAgIG5hID0gYygiI0VSUk9SIikpCgojIHJlYWwgcHJvcGVydHkgdGFibGUgZm9yIGJsY29rIGxvb2t1cCBpZiBuZWNlc3NhcnkKcmVhbF9wcm9wIDwtIHJlYWRfY3N2KCIuLi9kYXRhL3Jhdy9SZWFsX1Byb3BlcnR5X1RheGVzLmNzdiIpCgojIHdvcmsgb3JkZXIgZGF0YSBmcm9tIENISVAgdGFibGUgb24gU1FMIGRiCndvX3NxbCA8LSByZWFkX2V4Y2VsKCIuLi9kYXRhL3Jhdy9jaGlwL0NISVBfV09fc3FsLnhsc3giLAogICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSAidGV4dCIsCiAgICAgICAgICAgICAgICAgICAgIG5hID0gIk4vQSIpICU+JQogIG11dGF0ZShgRGF0ZSBDcmVhdGVgID0gYXMuRGF0ZShhcy5udW1lcmljKGBEYXRlIENyZWF0ZWApLCBvcmlnaW4gPSAiMTg5OS0xMi0zMCIpKSAlPiUKICBmaWx0ZXIoYERhdGUgQ3JlYXRlYCA+PSAiMjAxOC0wMS0wMSIpCgojIHBhcmNlbHMgc2hhcGVmaWxlIGZyb20gT3BlbiBCYWx0aW1vcmUKcGFyY2VscyA8LSByZWFkT0dSKCIuLi9kYXRhL3Jhdy9wYXJjZWxzL3BhcmNlbHMuc2hwIiwgdmVyYm9zZSA9IEYpCgpzdHJlZXRfc2VnbWVudHMgPC0gcmVhZE9HUigiLi4vZGF0YS9yYXcvQnVmZmVyX29mX1N0cmVldHNfYW5kXzMxMV92My9CdWZmZXJfb2ZfU3RyZWV0c19hbmRfMzExX3YzLnNocCIsIHZlcmJvc2UgPSBGKQoKcXVhZHMgPC0gcmVhZE9HUigiLi4vZGF0YS9yYXcvRFBXIFF1YWRyYW50IFNoYXBlZmlsZS9TV19RdWFkcmFudHNfUG9seWdvbl9OZXcuc2hwIiwgdmVyYm9zZSA9IEYpCgpwcm9tb3cgPC0gcmVhZF9leGNlbCgiLi4vZGF0YS9yYXcvUHJvTW93X01DQ1Byb3BlcnR5TGlzdF8yMDE5MDczMC54bHN4IikKCnF1YWRzIDwtIHNwVHJhbnNmb3JtKHF1YWRzLCBDUlMoIitpbml0PWVwc2c6NDMyNiIpKQoKaG9vZHMgPC0gcmVhZFJEUygiLi4vZGF0YS9wcm9jZXNzZWQvaG9vZHMuUmRzIikKYGBgCgoKCgpgYGB7cn0KZHB3X2ZhY2lsaXRpZXMgPC0gYygiNDE3IEUgRkFZRVRURSBTVCIsCiAgICAgICAgICAgICAgICAgICAgIjM5MzkgUkVJU1RFUlNUT1dOIFJEIiwKICAgICAgICAgICAgICAgICAgICAiMzQxMSBCQU5LIFNUIiwKICAgICAgICAgICAgICAgICAgICAiNTIyNSBZT1JLIFJEIikKYGBgCgpgYGB7cn0Kc2YgPC0gc2Zfc3cgJT4lIAogIGJpbmRfcm93cyhzZl9oY2QpICU+JQogIGJpbmRfcm93cyhzZl9zaXUpICU+JQogIGJpbmRfcm93cyhzZl9kaXJ0eSkgJT4lCiAgcmVwbGFjZV9uYShsaXN0KGBCbG9jayBOdW1iZXJgID0gIiIsIGBTdHJlZXQgTm9gID0gIiIsIGBTdHJlZXQgTmFtZWAgPSAiIikpICU+JQogIG11dGF0ZShkYXRlX29wZW5lZCA9IGFzLkRhdGUoYXMubnVtZXJpYyhgT3BlbmVkIERhdGVgKSwgb3JpZ2luID0gIjE4OTktMTItMzAiKSwKICAgICAgICAgbGF0ID0gYXMubnVtZXJpYyhgTG9jYXRpb24gKExhdGl0dWRlKWApLAogICAgICAgICBsb25nID0gYXMubnVtZXJpYyhgTG9jYXRpb24gKExvbmdpdHVkZSlgKSwKICAgICAgICAgc3RyZWV0X2FkZHJlc3MgPSBwYXN0ZShgU3RyZWV0IE5vYCwgYFN0cmVldCBOYW1lYCkpICU+JQogIHJlbmFtZShzdHJlZXRfbmFtZSA9IGBTdHJlZXQgTmFtZWApICU+JSAKICBsZWZ0X2pvaW4ocmVhbF9wcm9wLCBieSA9IGMoInN0cmVldF9hZGRyZXNzIiA9ICJQcm9wZXJ0eUFkZHJlc3MiKSkgJT4lCiAgbXV0YXRlKHN0cmVldF9udW0gPSBhcy5udW1lcmljKGBTdHJlZXQgTm9gKSkKCndvX3NxbCA8LSB3b19zcWwgJT4lCiAgbXV0YXRlKGBDbGVhbiBUeXBlYCA9IGlmZWxzZShpcy5uYShgQ2xlYW4gVHlwZWApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCT0FSRElORyAobm90IGNsZWFuaW5nKSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYENsZWFuIFR5cGVgKSkgJT4lCiAgcmVwbGFjZV9uYShsaXN0KERpcmVjdGlvbiA9ICIiLCBgU3RyZWV0IE5hbWVgID0gIiIsIGBTdHJlZXQgQXR0cmAgPSAiIikpICU+JQogIG11dGF0ZShkYXRlX2NyZWF0ZWQgPSBhcy5EYXRlKGBEYXRlIENyZWF0ZWApLAogICAgICAgICBzdHJlZXRfYWRkcmVzcyA9IHBhc3RlKGBIb3VzZSBOdW1iZXJgLCBEaXJlY3Rpb24sIGBTdHJlZXQgTmFtZWAsIGBTdHJlZXQgQXR0cmApLAogICAgICAgICBzdHJlZXRfbmFtZSA9IHBhc3RlKERpcmVjdGlvbiwgYFN0cmVldCBOYW1lYCwgYFN0cmVldCBBdHRyYCksCiAgICAgICAgIHN0cmVldF9udW0gPSBhcy5udW1lcmljKGBIb3VzZSBOdW1iZXJgKSkKYGBgCgpgYGB7cn0Kc2ZfYWRkcmVzc19jb3VudHMgPC0gc2YgJT4lIAogIGZpbHRlcigKICAgICAgICAgZGF0ZV9vcGVuZWQgPj0gIjIwMTgtMDEtMDEiLAogICAgICAgICAhaXMubmEoc3RyZWV0X251bSksCiAgICAgICAgICFpcy5uYShzdHJlZXRfbmFtZSksCiAgICAgICAgICEoc3RyZWV0X2FkZHJlc3MgJWluJSBkcHdfZmFjaWxpdGllcykpICU+JQogIGNvdW50KEJsb2NrLCBzdHJlZXRfbnVtLCBzdHJlZXRfbmFtZSwgYFNlcnZpY2UgUmVxdWVzdCBUeXBlYCkgJT4lCiAgc3ByZWFkKGtleSA9IGBTZXJ2aWNlIFJlcXVlc3QgVHlwZWAsIAogICAgICAgICB2YWx1ZSA9IG4pICU+JQogIHJlcGxhY2VfbmEobGlzdChgSENELUlsbGVnYWwgRHVtcGluZ2AgPSAwLAogICAgICAgICAgICAgICAgICBgSENELVNhbml0YXRpb24gUHJvcGVydHlgID0gMCwKICAgICAgICAgICAgICAgICAgYEhDRC1WYWNhbnQgQnVpbGRpbmdgID0gMCwKICAgICAgICAgICAgICAgICAgYFNXLUJvYXJkaW5nYCA9IDAsCiAgICAgICAgICAgICAgICAgIGBTVy1DbGVhbmluZ2AgPSAwLAogICAgICAgICAgICAgICAgICBgU1ctSEdXYCA9IDAsCiAgICAgICAgICAgICAgICAgIGBTVy1TSVUgQ2xlYW4gVXBgID0gMCwKICAgICAgICAgICAgICAgICAgYFNXLURpcnR5IEFsbGV5YCA9IDAsCiAgICAgICAgICAgICAgICAgIGBTVy1EaXJ0eSBTdHJlZXRgID0gMCwKICAgICAgICAgICAgICAgICAgYFNXLURpcnR5IEFsbGV5IFByb2FjdGl2ZWAgPSAwLAogICAgICAgICAgICAgICAgICBgU1ctRGlydHkgU3RyZWV0IFByb2FjdGl2ZWAgPSAwKSkgJT4lCiAgbXV0YXRlKHNmX2NvdW50ID0gYEhDRC1JbGxlZ2FsIER1bXBpbmdgICsKICAgICAgICAgICBgSENELVNhbml0YXRpb24gUHJvcGVydHlgICsKICAgICAgICAgICBgSENELVZhY2FudCBCdWlsZGluZ2AgKwogICAgICAgICAgIGBTVy1Cb2FyZGluZ2AgKwogICAgICAgICAgIGBTVy1DbGVhbmluZ2AgKwogICAgICAgICAgIGBTVy1IR1dgICsKICAgICAgICAgICBgU1ctU0lVIENsZWFuIFVwYCArCiAgICAgICAgICAgYFNXLURpcnR5IEFsbGV5YCArCiAgICAgICAgICAgYFNXLURpcnR5IFN0cmVldGAgKwogICAgICAgICAgIGBTVy1EaXJ0eSBBbGxleSBQcm9hY3RpdmVgICsKICAgICAgICAgICBgU1ctRGlydHkgU3RyZWV0IFByb2FjdGl2ZWAKCiAgKQoKYGBgCgoKCmBgYHtyfQp3b19hZGRyZXNzX2NvdW50cyA8LSB3b19zcWwgJT4lIAogIGZpbHRlcihkYXRlX2NyZWF0ZWQgPj0gIjIwMTgtMDEtMDEiLAogICAgICAgICBgQ2xlYW4gVHlwZWAgJWluJSBjKCJISUdIIEdSQVNTICYgV0VFRFMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJUUkFTSCAmIERFQlJJUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSQVNILCBERUJSSVMsIEhJR0ggR1JBU1MgJiBXRUVEUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkJPQVJESU5HIChub3QgY2xlYW5pbmcpIiksCiAgICAgICAgICFpcy5uYShzdHJlZXRfYWRkcmVzcyksCiAgICAgICAgICFncmVwbCgiRGVzY3JpcHRpdmUiLCBzdHJlZXRfbmFtZSksCiAgICAgICAgICEoc3RyZWV0X2FkZHJlc3MgJWluJSBkcHdfZmFjaWxpdGllcykpICU+JQogIGNvdW50KEJsb2NrLCBzdHJlZXRfbnVtLCBzdHJlZXRfbmFtZSwgYENsZWFuIFR5cGVgKSAlPiUgCiAgc3ByZWFkKGtleSA9IGBDbGVhbiBUeXBlYCwgdmFsdWUgPSBuKSAlPiUKICByZXBsYWNlX25hKGxpc3QoCiAgICAiSElHSCBHUkFTUyAmIFdFRURTIiA9IDAgLAogICAgIlRSQVNIICYgREVCUklTIiA9IDAsCiAgICAiVFJBU0gsIERFQlJJUywgSElHSCBHUkFTUyAmIFdFRURTIiA9IDAsCiAgICAiQk9BUkRJTkcgKG5vdCBjbGVhbmluZykiID0gMCkpICU+JQogIG11dGF0ZSh3b19jb3VudCA9IGBISUdIIEdSQVNTICYgV0VFRFNgICsgCiAgICAgICAgICAgYFRSQVNIICYgREVCUklTYCArCiAgICAgICAgICAgYFRSQVNILCBERUJSSVMsIEhJR0ggR1JBU1MgJiBXRUVEU2AgKwogICAgICAgICAgIGBCT0FSRElORyAobm90IGNsZWFuaW5nKWApCgp3b19jYXQyM19hZGRyZXNzX2NvdW50cyA8LSB3b19zcWwgJT4lIAogIGZpbHRlcihkYXRlX2NyZWF0ZWQgPj0gIjIwMTgtMDEtMDEiLAogICAgICAgICBgQ2xlYW4gVHlwZWAgJWluJSBjKCJISUdIIEdSQVNTICYgV0VFRFMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJUUkFTSCAmIERFQlJJUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSQVNILCBERUJSSVMsIEhJR0ggR1JBU1MgJiBXRUVEUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkJPQVJESU5HIChub3QgY2xlYW5pbmcpIiksCiAgICAgICAgICFpcy5uYShzdHJlZXRfYWRkcmVzcyksCiAgICAgICAgICFncmVwbCgiRGVzY3JpcHRpdmUiLCBzdHJlZXRfbmFtZSksCiAgICAgICAgICEoc3RyZWV0X2FkZHJlc3MgJWluJSBkcHdfZmFjaWxpdGllcyksCiAgICAgICAgIGBDbGVhbiBTaXplYCAlaW4lIGMoMiwgMykpICU+JQogIGNvdW50KEJsb2NrLCBzdHJlZXRfbnVtLCBzdHJlZXRfbmFtZSwgYENsZWFuIFR5cGVgKSAlPiUgCiAgc3ByZWFkKGtleSA9IGBDbGVhbiBUeXBlYCwgdmFsdWUgPSBuKSAlPiUKICByZXBsYWNlX25hKGxpc3QoCiAgICAiSElHSCBHUkFTUyAmIFdFRURTIiA9IDAgLAogICAgIlRSQVNIICYgREVCUklTIiA9IDAsCiAgICAiVFJBU0gsIERFQlJJUywgSElHSCBHUkFTUyAmIFdFRURTIiA9IDAsCiAgICAiQk9BUkRJTkcgKG5vdCBjbGVhbmluZykiID0gMCkpICU+JQogIHJlbmFtZShoZ3dfY2F0MjMgPSAiSElHSCBHUkFTUyAmIFdFRURTIiwKICAgICAgICAgdGRfY2F0MjMgPSAiVFJBU0ggJiBERUJSSVMiLAogICAgICAgICB0ZF9oZ3dfY2F0MjMgPSAiVFJBU0gsIERFQlJJUywgSElHSCBHUkFTUyAmIFdFRURTIikgJT4lCiAgbXV0YXRlKHdvX2NhdDIzX2NvdW50ID0gaGd3X2NhdDIzICsgdGRfY2F0MjMgKyB0ZF9oZ3dfY2F0MjMpCmBgYAoKIyMgQ291bnRzIGJ5IEFkZHJlc3MKCmBgYHtyfQphZGRyZXNzX2NvdW50c19qb2luIDwtIHdvX2FkZHJlc3NfY291bnRzICU+JQogIGZ1bGxfam9pbihzZl9hZGRyZXNzX2NvdW50cywgCiAgICAgICAgICAgIGJ5ID0gYygic3RyZWV0X251bSIsICJzdHJlZXRfbmFtZSIpKSAlPiUKICBmdWxsX2pvaW4od29fY2F0MjNfYWRkcmVzc19jb3VudHMgJT4lIAogICAgICAgICAgICAgIHNlbGVjdCgKICAgICAgICAgICAgICAgIHN0cmVldF9udW0sCiAgICAgICAgICAgICAgICBzdHJlZXRfbmFtZSwKICAgICAgICAgICAgICAgIGhnd19jYXQyMywKICAgICAgICAgICAgICAgIHRkX2NhdDIzLAogICAgICAgICAgICAgICAgdGRfaGd3X2NhdDIzLAogICAgICAgICAgICAgICAgd29fY2F0MjNfY291bnQKICAgICAgICAgICAgICApLCAKICAgICAgICAgICAgYnkgPSBjKCJzdHJlZXRfbnVtIiwgInN0cmVldF9uYW1lIikpICU+JQogIHJlcGxhY2VfbmEobGlzdCgKICAgIGBISUdIIEdSQVNTICYgV0VFRFNgID0gMCwKICAgIGBUUkFTSCAmIERFQlJJU2AgPSAwLAogICAgYFRSQVNILCBERUJSSVMsIEhJR0ggR1JBU1MgJiBXRUVEU2AgPSAwLAogICAgYEJPQVJESU5HIChub3QgY2xlYW5pbmcpYCA9IDAsCiAgICBgSENELUlsbGVnYWwgRHVtcGluZ2AgPSAwLAogICAgYEhDRC1TYW5pdGF0aW9uIFByb3BlcnR5YCA9IDAsCiAgICBgSENELVZhY2FudCBCdWlsZGluZ2AgPSAwLAogICAgYFNXLUJvYXJkaW5nYCA9IDAsCiAgICBgU1ctQ2xlYW5pbmdgID0gMCwKICAgIGBTVy1IR1dgID0gMCwKICAgIGBTVy1TSVUgQ2xlYW4gVXBgID0gMCwKICAgIGBTVy1EaXJ0eSBBbGxleWAgPSAwLAogICAgYFNXLURpcnR5IFN0cmVldGAgPSAwLAogICAgYFNXLURpcnR5IEFsbGV5IFByb2FjdGl2ZWAgPSAwLAogICAgYFNXLURpcnR5IFN0cmVldCBQcm9hY3RpdmVgID0gMCwKICAgIHdvX2NvdW50ID0gMCwKICAgIHNmX2NvdW50ID0gMCwKICAgIGhnd19jYXQyMyA9IDAsCiAgICB0ZF9jYXQyMyA9IDAsCiAgICB0ZF9oZ3dfY2F0MjMgPSAwLAogICAgd29fY2F0MjNfY291bnQgPSAwKSkgJT4lCiAgbXV0YXRlKGFsbF9ldmVudHMgPSB3b19jb3VudCArIHNmX2NvdW50LAogICAgICAgICBkaWZmX2V2ZW50cyA9IHdvX2NvdW50IC0gc2ZfY291bnQsCiAgICAgICAgIEJsb2NrID0gaWZlbHNlKCFpcy5uYShCbG9jay54KSwgQmxvY2sueCwgQmxvY2sueSksCiAgICAgICAgIHJlcG9ydGluZyA9IGBIQ0QtSWxsZWdhbCBEdW1waW5nYCArIGBIQ0QtU2FuaXRhdGlvbiBQcm9wZXJ0eWAsCiAgICAgICAgIGNsZWFudXAgPSAgYFNXLURpcnR5IEFsbGV5YCArIGBTVy1EaXJ0eSBTdHJlZXRgICsgCiAgICAgICAgIGBTVy1EaXJ0eSBBbGxleSBQcm9hY3RpdmVgICsgYFNXLURpcnR5IFN0cmVldCBQcm9hY3RpdmVgCiAgICAgICAgICsgYFNXLVNJVSBDbGVhbiBVcGAgKyB3b19jYXQyM19jb3VudCkKCmFkZHJlc3NfY291bnRzX2pvaW4KYGBgCgoKCiMjIENvdW50cyBieSBCbG9jawoKYGBge3J9CmJsb2NrX2NvdW50cyA8LSBhZGRyZXNzX2NvdW50c19qb2luICU+JQogIGZpbHRlcighaXMubmEoQmxvY2spKSAlPiUKICBzZWxlY3QoLXN0cmVldF9udW0sIC1zdHJlZXRfbmFtZSwgLUJsb2NrLngsIC1CbG9jay55LCAtZGlmZl9ldmVudHMpICU+JQogIGdyb3VwX2J5KEJsb2NrKSAlPiUKICBzdW1tYXJpc2VfYWxsKHN1bSwgbmEucm09VCkgJT4lCiAgdW5ncm91cCgpICU+JQogIGFycmFuZ2UoZGVzYyhhbGxfZXZlbnRzKSkgCgpibG9ja19jb3VudHMKYGBgCgpCZWxvd3MgaXMgYSBjdW11bGF0aXZlIHBlcmNlbnRhZ2UgcGxvdCBzaG93aW5nIHRoZSBudW1iZXIgb2YgYmxvY2tzIHJlc3BvbnNpYmxlIGZvciBhIGdpdmVuIHBlcmNlbnRhZ2Ugb2YgY2F0ZWdvcnkgMyB3b3JrIG9yZGVycy4KCioqMTg5IGJsb2Nrcywgb3IgMTQlIG9mIGFsbCBibG9ja3MgcmVjZWl2aW5nIGEgY2F0ZWdvcnkgMyB3b3JrIG9yZGVyIHNpbmNlIEphbnVhcnkgMSwgMjAxOCwgYXJlIHJlc3BvbnNpYmxlIGZvciA1MCUgb2YgYWxsIGNhdGVnb3J5IDMgd29yayBvcmRlcnMuKioKCmBgYHtyIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSAyfQp4IDwtIDAuMjUKIyBSZXNwb25zaWJsZSBmb3IgNTAlIG9mIHdvcmsgb3JkZXJzCndvX2N1bSA8LSB3b19zcWwgJT4lCiAgZmlsdGVyKGBDbGVhbiBTaXplYCA9PSAzLAogICAgICAgICBkYXRlX2NyZWF0ZWQgPj0gIjIwMTgtMDEtMDEiLAogICAgICAgICBgQ2xlYW4gVHlwZWAgJWluJSBjKCJISUdIIEdSQVNTICYgV0VFRFMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUkFTSCAmIERFQlJJUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSQVNILCBERUJSSVMsIEhJR0ggR1JBU1MgJiBXRUVEUyIpLAogICAgICAgICAjIWlzLm5hKHN0cmVldF9hZGRyZXNzKSwKICAgICAgICAgIWdyZXBsKCJEZXNjcmlwdGl2ZSIsIHN0cmVldF9uYW1lKSwKICAgICAgICAgIShzdHJlZXRfYWRkcmVzcyAlaW4lIGRwd19mYWNpbGl0aWVzKSkgJT4lCiAgY291bnQoQmxvY2spICU+JQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lCiAgbXV0YXRlKHJvd19uID0gcm93X251bWJlcigpLAogICAgICAgICBjdW1fYmxvY2tzID0gcm93X24gLyBtYXgocm93X24pLAogICAgICAgICBjdW1zdW1fc3IgPSBjdW1zdW0obiksCiAgICAgICAgIGN1bXBjdF9zciA9IGN1bXN1bV9zciAvIHN1bShuKSkKCndvX2N1bV81MHBjdCA8LSB3b19jdW0gJT4lCiAgZmlsdGVyKGFicyh4IC0gY3VtcGN0X3NyKSA9PSBtaW4oYWJzKHggLSBjdW1wY3Rfc3IpKSkgJT4lCiAgc2VsZWN0KHJvd19uKSAlPiUKICBwdWxsKCkKCndvX2N1bSAlPiUKICBnZ3Bsb3QoYWVzKHJvd19uLCBjdW1wY3Rfc3IpKSArCiAgZ2VvbV9saW5lKCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgI3RoZW1lX2l0ZWFtX2dvb2dsZV9kb2NzKCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICBsYWJzKHggPSAiTnVtYmVyIG9mIENpdHkgQmxvY2tzIiwKICAgICAgIHkgPSAiJSBDYXRlZ29yeSAzIENsZWFuaW5nIikKYGBgCgpgYGB7cn0Kd29fY3VtXzUwcGN0X2RmIDwtIHdvX2N1bSAlPiUKICBmaWx0ZXIocm93X24gPD13b19jdW1fNTBwY3QpCgp3b19jdW1fNTBwY3RfcGFyY2VscyA8LSBzdWJzZXQocGFyY2VscywgcGFyY2VscyRCTE9DS05VTSAlaW4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29fY3VtXzUwcGN0X2RmJEJsb2NrKQpgYGAKCiMgTWFwCgpgYGB7cn0KYmxvY2tfdG9wMTAwX3JlcG9ydGluZyA8LSBibG9ja19jb3VudHMgJT4lCiAgYXJyYW5nZShkZXNjKHJlcG9ydGluZykpICU+JQogIHRvcF9uKDEwMCwgcmVwb3J0aW5nKSAlPiUKICBtdXRhdGUoaWRfcmFuayA9IHJvd19udW1iZXIoKSkKCmJsb2NrX3RvcDEwMF9jbGVhbnVwIDwtIGJsb2NrX2NvdW50cyAlPiUKICBhcnJhbmdlKGRlc2MoY2xlYW51cCkpICU+JQogIHRvcF9uKDEwMCwgY2xlYW51cCkgJT4lCiAgbXV0YXRlKGlkX3JhbmsgPSByb3dfbnVtYmVyKCkpCgpibG9ja190b3AxMDBfcmVwb3J0aW5nX2NsZWFudXAgPC0gYmxvY2tfdG9wMTAwX3JlcG9ydGluZyAlPiUKICBpbm5lcl9qb2luKGJsb2NrX3RvcDEwMF9jbGVhbnVwLCBieSA9ICJCbG9jayIpCmBgYAoKCmBgYHtyfQpibG9ja190b3AxMDBfcmVwb3J0aW5nX3BhcmNlbHMgPC0gc3Vic2V0KHBhcmNlbHMsIHBhcmNlbHMkQkxPQ0tOVU0gJWluJQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsb2NrX3RvcDEwMF9yZXBvcnRpbmckQmxvY2spCgpibG9ja190b3AxMDBfY2xlYW51cF9wYXJjZWxzIDwtIHN1YnNldChwYXJjZWxzLCBwYXJjZWxzJEJMT0NLTlVNICVpbiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmxvY2tfdG9wMTAwX2NsZWFudXAkQmxvY2spCgpvcGVuX3dvIDwtIHdvX3NxbCAlPiUgZmlsdGVyKFN0YXR1cyAlaW4lIGMoIk5FVyIsICJQRU5ESU5HIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKExhdGl0dWRlKSkgJT4lCiAgbXV0YXRlKExhdGl0dWRlID0gYXMubnVtZXJpYyhMYXRpdHVkZSksCiAgICAgICAgIExvbmdpdHVkZSA9IGFzLm51bWVyaWMoTG9uZ2l0dWRlKSkKCm9wZW5fc3IgPC0gc2YgJT4lIGZpbHRlcihpcy5uYShgQ2xvc2VkIERhdGVgKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGBEYXRlL1RpbWUgT3BlbmVkYCA+PSAiMjAxOC0wMS0wMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoYExvY2F0aW9uIChMYXRpdHVkZSlgKSkgJT4lCiAgbXV0YXRlKGBMb2NhdGlvbiAoTGF0aXR1ZGUpYCA9IGFzLm51bWVyaWMoYExvY2F0aW9uIChMYXRpdHVkZSlgKSwKICAgICAgICAgYExvY2F0aW9uIChMb25naXR1ZGUpYCA9IGFzLm51bWVyaWMoYExvY2F0aW9uIChMb25naXR1ZGUpYCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0ID0gNn0KbGlicmFyeShodG1sdG9vbHMpCnRvcF9zdHJlZXRfc2VnbWVudHMgPC0gc3Vic2V0KHN0cmVldF9zZWdtZW50cykKCm1hcF9jb2xvcnMgPC0gYygiYmxhY2siLAogICAgICAgICAgICAgICAgaXRlYW0uY29sb3JzWzVdLAogICAgICAgICAgICAgICAgaXRlYW0uY29sb3JzWzFdLAogICAgICAgICAgICAgICAgaXRlYW0uY29sb3JzWzRdLAogICAgICAgICAgICAgICAgIyJibHVlIiwKICAgICAgICAgICAgICAgICMicmVkIiwKICAgICAgICAgICAgICAgIGl0ZWFtLmNvbG9yc1szXSkKCm1hcF9sYWJlbHMgPC0gYygiUXVhZHJhbnQiLAogICAgICAgICAgICAgICAgIlRvcCAxMDAgZm9yIEluc3BlY3Rpb24vSW52ZXN0aWdhdGlvbiIsIAogICAgICAgICAgICAgICAgIlRvcCAxMDAgZm9yIENsZWFuaW5nIEFjdGl2aXR5IiwKICAgICAgICAgICAgICAgICI1MCUgb2YgQ2F0IDMgV29yayBPcmRlcnMiLAogICAgICAgICAgICAgICAgIyJPcGVuIFdvcmsgT3JkZXJzIiwKICAgICAgICAgICAgICAgICMiT3BlbiBTZXJ2aWNlIFJlcXVlc3RzIiwKICAgICAgICAgICAgICAgICJOZWlnaGJvcmhvb2RzIikKCm9wZW5fd29fbGFiZWxzIDwtIHBhc3RlMCgiT3BlbiBXb3JrIE9yZGVyIiwgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgb3Blbl93byRgU3RyZWV0IEFkZHJlc3NgLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICBvcGVuX3dvJGBQcm9wZXJ0eSBPd25lcmAsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgIG9wZW5fd28kYFdvcmsgT3JkZXIgVHlwZWAsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgIG9wZW5fd28kYENsZWFuIFR5cGVgLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiQ2F0ZWdvcnk6ICIsIG9wZW5fd28kYENsZWFuIFNpemVgKQoKb3Blbl9zcl9sYWJlbHMgPC0gcGFzdGUwKCJPcGVuIFNlcnZpY2UgUmVxdWVzdCA8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgIG9wZW5fc3Ikc3RyZWV0X2FkZHJlc3MsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgIG9wZW5fc3IkYFNlcnZpY2UgUmVxdWVzdCBUeXBlYCwgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgb3Blbl9zciRgQWN0aXZpdHkgQXNzaWduZWQgVG9gLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiRGF0ZSBPcGVuZW5kOiAiLCBvcGVuX3NyJGBPcGVuZWQgRGF0ZWApCmxlYWZsZXQoKSAlPiUKICBzZXRWaWV3KGxuZyA9IC03Ni42LCBsYXQgPSAzOS4zLCB6b29tID0gMTIpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJFN0YW1lbi5Ub25lckxpdGUpICU+JSAKICAgIGFkZFBvbHlnb25zKGRhdGEgPSBxdWFkcywKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAsCiAgICAgICAgICAgICAgb3BhY2l0eSA9IDEsCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIHdlaWdodCA9IDMsCiAgICAgICAgICAgICAgZ3JvdXAgPSBtYXBfbGFiZWxzWzFdKSAlPiUKICBhZGRQb2x5Z29ucyhkYXRhID0gaG9vZHMsCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLAogICAgICAgICAgICAgIG9wYWNpdHkgPSAxLAogICAgICAgICAgICAgIGNvbG9yID0gbWFwX2NvbG9yc1s1XSwKICAgICAgICAgICAgICB3ZWlnaHQgPSAxLjUsCiAgICAgICAgICAgICAgZ3JvdXAgPSBtYXBfbGFiZWxzWzVdLAogICAgICAgICAgICAgIGxhYmVsID0gfmhvb2RzJGxhYmVsKSAlPiUKICBhZGRQb2x5Z29ucyhkYXRhID0gYmxvY2tfdG9wMTAwX3JlcG9ydGluZ19wYXJjZWxzLAogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC42LAogICAgICAgICAgICAgIGZpbGxDb2xvciA9IG1hcF9jb2xvcnNbMl0sCiAgICAgICAgICAgICAgb3BhY2l0eSA9IDAsCiAgICAgICAgICAgICAgZ3JvdXAgPSBtYXBfbGFiZWxzWzJdKSAlPiUKICBhZGRQb2x5Z29ucyhkYXRhID0gYmxvY2tfdG9wMTAwX2NsZWFudXBfcGFyY2VscywKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNiwKICAgICAgICAgICAgICBmaWxsQ29sb3IgPSBtYXBfY29sb3JzWzNdLAogICAgICAgICAgICAgIG9wYWNpdHkgPSAwLAogICAgICAgICAgICAgIGdyb3VwID0gbWFwX2xhYmVsc1szXSkgJT4lCiAgICBhZGRQb2x5Z29ucyhkYXRhID0gd29fY3VtXzUwcGN0X3BhcmNlbHMsCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjYsCiAgICAgICAgICAgICAgZmlsbENvbG9yID0gbWFwX2NvbG9yc1s0XSwKICAgICAgICAgICAgICBvcGFjaXR5ID0gMCwKICAgICAgICAgICAgICBncm91cCA9IG1hcF9sYWJlbHNbNF0pICU+JQogICMgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gb3Blbl93bywKICAjICAgICAgICAgICAgICAgICAgbGF0ID0gb3Blbl93byRMYXRpdHVkZSwKICAjICAgICAgICAgICAgICAgICAgbG5nID0gb3Blbl93byRMb25naXR1ZGUsCiAgIyAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDIsCiAgIyAgICAgICAgICAgICAgICAgIGxhYmVsID0gfmxhcHBseShvcGVuX3dvX2xhYmVscywgSFRNTCksCiAgIyAgICAgICAgICAgICAgICAgIGdyb3VwID0gbWFwX2xhYmVsc1s1XSwKICAjICAgICAgICAgICAgICAgICAgZmlsbENvbG9yID0gbWFwX2NvbG9yc1s1XSwKICAjICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDApICU+JQogICMgICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBvcGVuX3NyLAogICMgICAgICAgICAgICAgICAgICBsYXQgPSBvcGVuX3NyJGBMb2NhdGlvbiAoTGF0aXR1ZGUpYCwKICAjICAgICAgICAgICAgICAgICAgbG5nID0gb3Blbl9zciRgTG9jYXRpb24gKExvbmdpdHVkZSlgLAogICMgICAgICAgICAgICAgICAgICByYWRpdXMgPSAyLAogICMgICAgICAgICAgICAgICAgICBsYWJlbCA9IH5sYXBwbHkob3Blbl9zcl9sYWJlbHMsIEhUTUwpLAogICMgICAgICAgICAgICAgICAgICBncm91cCA9IG1hcF9sYWJlbHNbNl0sCiAgIyAgICAgICAgICAgICAgICAgIGZpbGxDb2xvciA9IG1hcF9jb2xvcnNbNl0sCiAgIyAgICAgICAgICAgICAgICAgIG9wYWNpdHkgPSAwKSAlPiUKICBhZGRMYXllcnNDb250cm9sKG92ZXJsYXlHcm91cHMgPSBtYXBfbGFiZWxzKSAlPiUKICBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLAogICAgICAgICAgICBjb2xvcnMgPSBtYXBfY29sb3JzLAogICAgICAgICAgICBsYWJlbHMgPSBtYXBfbGFiZWxzKQoKYGBg